import { ApiMsgEnum, IModel, GWsAddress, Singleton } from "../Common";
import { binaryDecode, binaryEncode } from "../Common/common/Binary";
import { showToast } from "./MainManager";
export interface IItem {
    fun: Function,
    ctx: unknown
}
export interface IApiCallRet<T> {
    success: boolean,
    res?: T,
    error: string,
}
export class NetworkManager extends Singleton {
    static get Ins() {
        return super.GetInstance<NetworkManager>()
    }

    isConnected = false
    private port = 8888
    private ws: WebSocket
    private map: Map<ApiMsgEnum, IItem[]> = new Map()

    /** 连接服务器 */
    async connect() {

        return new Promise((resolve, reject) => {

            this.ws = new WebSocket(`${GWsAddress}:${this.port}`)
            this.ws.binaryType = 'arraybuffer'
            this.ws.onclose = (e: CloseEvent) => {
                console.log('websocket close:' + e.code)
                this.isConnected = false
                reject(false)
            }

            this.ws.onerror = (e: Event) => {
                console.log('websocket error:' + e.type)
                reject(false)
            }

            this.ws.onopen = (e: Event) => {
                console.log('websocket open:' + e.type)
                this.isConnected = true
                resolve(true)
            }

            this.ws.onmessage = (e: MessageEvent) => {
                try {
                    const json = binaryDecode(e.data)
                    const { name, data } = json
                    try {
                        if (this.map.has(name)) {
                            const cb = this.map.get(name)
                            cb.forEach(({ fun, ctx }) => {
                                fun.call(ctx, data)
                            })
                        }
                    } catch (error) {
                        console.log('onmessage: ', error)
                    }
                } catch (error) {
                    console.log('解析失败，不是合法的json', error)
                }
            }
        })
    }

    /** 调用api */
    callApi<T extends keyof IModel['api']>(name: T, data: IModel['api'][T]['req']): Promise<IApiCallRet<IModel['api'][T]['res']>> {
        let listenName = name as any
        return new Promise((resolve) => {
            try {
                const timer = setTimeout(() => {
                    this.unlistening(listenName, cb, this)
                    resolve({
                        success: false,
                        error: '请求超时'
                    })
                    console.log('api time out:' + listenName)
                }, 5000);

                const cb = (res: IApiCallRet<IModel['api'][T]['res']>) => {
                    clearTimeout(timer)
                    resolve(res)
                    console.log(`服务器返回:${listenName}=>${JSON.stringify(res)}`)
                    if (!res.success) {
                        showToast(res.error)
                    }
                    this.unlistening(listenName, cb, this)
                }

                this.listening(listenName, cb, this)
                this.send(listenName, data)
            } catch (error) {
                resolve({
                    success: false,
                    error
                })
            }
        })
    }

    listening<T extends keyof IModel['msg']>(name: T, fun: Function, ctx: unknown) {
        if (this.map.has(name)) {
            this.map.get(name).push({ ctx, fun })
        } else {
            this.map.set(name, [{ ctx, fun }])
        }
    }

    unlistening<T extends keyof IModel['msg']>(name: T, fun: Function, ctx: unknown) {
        if (this.map.has(name)) {
            const index = this.map.get(name).findIndex(v => v.fun === fun && v.ctx === ctx)
            index > -1 && this.map.get(name).splice(index, 1)
        }
    }

    send<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
        // console.log(name, data)
        this.ws.send(binaryEncode(name, data).buffer)
    }

}